package gcode.helloworld.java.socket.linecaller;

import java.io.IOException;
import java.net.BindException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

import org.apache.log4j.Logger;


public class Server {
	public static void main(String args[]){
		org.apache.log4j.BasicConfigurator.configure();
		Server s = new Server(9005);
		s.run();
		System.out.println("END");
	}
	private Logger log	= null;
	private BlockingQueue<Socket> queue	= null;
	private int port	= 0;
	private int maxQueueSize	= 100;
	private int maxWorkerCount = 10;
	private List<Worker>	workers	= null;
	private SocketListener listener	= null;
	private boolean running = false;
	
	public Server(int port){
		log = Logger.getLogger(getClass());
		this.port = port;
		maxWorkerCount = 10;
	}

	public void run(){
		log.info("run");
		running = true;
		queue = new ArrayBlockingQueue<Socket>(maxQueueSize);
		listener = new SocketListener(queue,port);
		startWorkers(maxWorkerCount );
		try {
			log.info("startListen");
			listener.listen();
			log.info("installShutdownHook");
			installShutdownHook();
			while(this.running){
				Thread.sleep(100);
			}
		} catch (BindException e){
			log.error("BindException "+port+" already in use!");
		} catch (IOException e) {
			log.error("listen Exception ",e);
		} catch (InterruptedException e) {
			log.error("Interrupted !",e);
		} finally{
			shutdown();
		}
	}

	private void startWorkers(int count) {
		log.info("startWorkers "+count);
		workers=new ArrayList<Worker>(count);
		for(int i=0 ; i<count; i++){
			Worker w = new Worker(queue);
			w.start();
			workers.add(w);
		}
	}
	public void shutdown(){
		log.info("SHUTDOWN");
		try { listener.shutdown(); } catch (InterruptedException e) { log.error("listener.shutdown Exception ",e); }
		for(Worker w:workers){
			try { w.shutdown();	} catch (InterruptedException e){ log.error("worker.shutdown Exception ",e); }
		}
	}

	private void installShutdownHook(){
		Runtime.getRuntime().addShutdownHook(new Thread(){
			public void run(){
				shutdown();
			}
		});
	}
	
}
